package com.zy.sso.client.secruity.filter;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.zy.sso.client.component.JwtTokenComponent;
import com.zy.sso.client.dto.login.RequestHeader;
import com.zy.sso.client.exception.SsoException;
import com.zy.sso.client.utils.RequestUtil;

import io.jsonwebtoken.Claims;

/**
 * 用户权限校验filter
 * **/
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
	
	private static final Logger logger =  LoggerFactory.getLogger(JwtAuthenticationTokenFilter.class);
	
	public static final String REQ_ATTR_JUER = "juser";
	
	public static final String REQ_ATTR_CLAIMS = "claims";
	
    @Autowired
    private JwtTokenComponent jwtTokenComponent;

    @Value("${jwt.header}")
    private String tokenHeader;

    @Value("${jwt.tokenHead}")
    private String tokenHead;
    
    @Value("${sso.fromSys}")
    private String fromSys;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        if(SecurityContextHolder.getContext().getAuthentication() != null) {
        	chain.doFilter(request, response);
        	return ;
        };
    	String authHeader = request.getHeader(tokenHeader);
        if (authHeader != null && authHeader.startsWith(tokenHead)) {
            final String authToken = authHeader.substring(tokenHead.length()); // The part after "Bearer "
            //parse token
            Claims claims = jwtTokenComponent.parseToken(authToken);
            if(claims == null) throw new SsoException("签名有误,请重新登录");
            //validateion sign
            RequestHeader requestHeader = RequestUtil.getJwtSignRequestHeader(request);
            if(!jwtTokenComponent.validateSign(requestHeader,claims)) throw new SsoException("签名错误,请重新登陆");
            //过期校验
            if(jwtTokenComponent.isTokenExpired(claims)) throw new SsoException("本次登陆已失效，请重新登陆");
            //刷新验证信息
            refreshAuth(request,response,claims);
            //check sys
            String sys = jwtTokenComponent.getCurrentSys(claims);
            if(!fromSys.equals(sys)){//跨系统处理
            	claims = jwtTokenComponent.overWriteBidAndRoles(claims);
            	//TODO refreshAuth
        		String token = jwtTokenComponent.refreshAuth(claims);
        		response.setHeader(tokenHeader, tokenHead + token);
            }
            //write auth content
            UserDetails userDetails = jwtTokenComponent.getUserDetails(claims);
            if (userDetails !=null && SecurityContextHolder.getContext().getAuthentication() == null) {
            	UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            	authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            	logger.info("authenticated user " + userDetails.getUsername() + ", setting security context");
            	SecurityContextHolder.getContext().setAuthentication(authentication);
            }
            //set attribute
            request.setAttribute(REQ_ATTR_JUER, userDetails);
            request.setAttribute(REQ_ATTR_CLAIMS, claims);
        }
        chain.doFilter(request, response);
    }
    
    
    /**过期时间校验
     * @throws UnsupportedEncodingException 
     * @throws JsonProcessingException 
     * **/
    private void refreshAuth(HttpServletRequest request,HttpServletResponse response ,Claims claims) throws UnsupportedEncodingException, JsonProcessingException{
    	Date exp = jwtTokenComponent.getExpirationDateFromToken(claims);
    	Instant instant = exp.toInstant();
    	ZoneId zone = ZoneId.systemDefault();
    	LocalDateTime expDateTime = LocalDateTime.ofInstant(instant, zone);
    	LocalDateTime now = LocalDateTime.now();
    	Duration duration = Duration.between(expDateTime, now);
    	if(duration.toMinutes() > 0 & duration.toMinutes() < 3 ){
    		//TODO refreshAuth
    		String token = jwtTokenComponent.refreshAuth(claims);
    		response.setHeader(tokenHeader, tokenHead + token);
    	}
    }
    
   
    
  
}
